﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace SignalEdgeDetectionWPF
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private readonly Random _rnd = new Random();
        private CancellationTokenSource _cts;
        private DispatcherTimer _uiUpdateTimer;
        private DateTime _lastUpdateTime;

        public ObservableCollection<SignalConfig> Signals { get; } = new ObservableCollection<SignalConfig>();

        private string _statusText = "状态: 已停止";
        public string StatusText {
            get => _statusText;
            set { _statusText = value; OnPropertyChanged(nameof(StatusText)); }
        }

        private string _statsText = "触发统计:";
        public string StatsText {
            get => _statsText;
            set { _statsText = value; OnPropertyChanged(nameof(StatsText)); }
        }

        private bool _isMonitoring;
        public bool IsMonitoring {
            get => _isMonitoring;
            set { _isMonitoring = value; OnPropertyChanged(nameof(IsMonitoring)); }
        }

        public ICommand StartCommand { get; }
        public ICommand StopCommand { get; }

        public event PropertyChangedEventHandler PropertyChanged;

        public MainViewModel()
        {
            InitializeSignals();

            StartCommand = new RelayCommand(async _ => await StartMonitoring());
            StopCommand = new RelayCommand(_ => StopMonitoring());

            SetupUiTimer();
        }

        private void InitializeSignals()
        {
            Signals.Add(new SignalConfig("DI1", "Start Button", true, 50));    // 常开信号
            Signals.Add(new SignalConfig("DI2", "Emergency Stop", false, 100)); // 常闭信号
            Signals.Add(new SignalConfig("DI3", "Sensor A", true, 80));
            Signals.Add(new SignalConfig("DI4", "Sensor B", false, 120));
        }

        private void SetupUiTimer()
        {
            _uiUpdateTimer = new DispatcherTimer {
                Interval = TimeSpan.FromMilliseconds(100)
            };
            _uiUpdateTimer.Tick += (s, e) => UpdateUi();
            _uiUpdateTimer.Start();
        }

        private async Task StartMonitoring()
        {
            if (IsMonitoring) return;

            IsMonitoring = true;
            StatusText = "状态: 运行中...";

            foreach (var signal in Signals) {
                signal.Reset();
            }

            _cts = new CancellationTokenSource();

            try {
                await Task.Run(() => MonitorSignals(_cts.Token), _cts.Token);
            }
            catch (OperationCanceledException) {
                Debug.WriteLine("监控已取消");
            }
        }

        private void StopMonitoring()
        {
            _cts?.Cancel();
            IsMonitoring = false;
            StatusText = "状态: 已停止";
        }

        private void MonitorSignals(CancellationToken ct)
        {
            Stopwatch sw = Stopwatch.StartNew();

            while (!ct.IsCancellationRequested) {
                long cycleStart = sw.ElapsedMilliseconds;

                // 模拟读取所有信号
                foreach (var signal in Signals) {
                    // 模拟实际信号（随机生成变化）
                    bool currentState = _rnd.Next(100) < 5 ? !signal.LastState : signal.LastState;

                    // 检测信号变化
                    bool triggered = CheckEdgeDetection(signal, currentState);

                    // 如果检测到有效边沿
                    if (triggered) {
                        signal.TriggerCount++;
                        signal.LastTriggerTime = DateTime.Now;
                        Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {signal.Name} 触发! (类型: {(signal.IsNO ? "常开" : "常闭")})");
                    }

                    // 保存当前状态
                    signal.LastState = currentState;
                    signal.CurrentState = currentState;
                }

                // 计算剩余时间并等待
                long elapsed = sw.ElapsedMilliseconds - cycleStart;
                if (elapsed < 50) {
                    Thread.Sleep(50 - (int)elapsed);
                }
                else {
                    Debug.WriteLine($"警告: 循环超时! 执行时间: {elapsed}ms");
                }
            }
        }

        private bool CheckEdgeDetection(SignalConfig signal, bool currentState)
        {
            // 首次检测，初始化状态
            if (signal.IsFirstCheck) {
                signal.LastState = currentState;
                signal.IsFirstCheck = false;
                return false;
            }

            // 状态没有变化
            if (currentState == signal.LastState) {
                return false;
            }

            // 检测有效边沿
            bool isValidEdge = false;

            // 常闭信号：检测下降沿 (高 -> 低)
            if (!signal.IsNO && signal.LastState && !currentState) {
                isValidEdge = true;
            }
            // 常开信号：检测上升沿 (低 -> 高)
            else if (signal.IsNO && !signal.LastState && currentState) {
                isValidEdge = true;
            }

            // 检查消抖时间
            if (isValidEdge) {
                var elapsed = (DateTime.Now - signal.LastTriggerTime).TotalMilliseconds;
                if (elapsed < signal.DebounceTime) {
                    return false; // 消抖期内忽略
                }

                return true;
            }

            return false;
        }

        private void UpdateUi()
        {
            // 更新统计信息
            int totalTriggers = Signals.Sum(s => s.TriggerCount);
            StatsText = $"触发统计: 总触发次数: {totalTriggers} | " +
                       string.Join(" | ", Signals.Select(s => $"{s.Name}: {s.TriggerCount}"));

            // 限制UI更新频率
            if ((DateTime.Now - _lastUpdateTime).TotalMilliseconds < 200) return;
            _lastUpdateTime = DateTime.Now;

            // 通知属性变化
            foreach (var signal in Signals) {
                signal.OnPropertiesChanged();
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class SignalConfig : INotifyPropertyChanged
    {
        public string Pin { get; }
        public string Name { get; }
        public bool IsNO { get; } // true=常开, false=常闭
        public int DebounceTime { get; } // 消抖时间(ms)

        private int _triggerCount;
        public int TriggerCount {
            get => _triggerCount;
            set { _triggerCount = value; OnPropertyChanged(nameof(TriggerCount)); }
        }

        private bool _lastState;
        public bool LastState {
            get => _lastState;
            set { _lastState = value; OnPropertyChanged(nameof(LastState)); }
        }

        private bool _currentState;
        public bool CurrentState {
            get => _currentState;
            set { _currentState = value; OnPropertyChanged(nameof(CurrentState)); }
        }

        public bool IsFirstCheck { get; set; } = true;
        public DateTime LastTriggerTime { get; set; } = DateTime.MinValue;

        public string SignalType => IsNO ? "常开" : "常闭";
        public Brush SignalTypeColor => IsNO ? Brushes.Green : Brushes.Blue;
        public Brush StateColor => CurrentState ? Brushes.Green : Brushes.Red;

        public event PropertyChangedEventHandler PropertyChanged;

        public SignalConfig(string pin, string name, bool isNO, int debounceTime)
        {
            Pin = pin;
            Name = name;
            IsNO = isNO;
            DebounceTime = debounceTime;
        }

        public void Reset()
        {
            TriggerCount = 0;
            IsFirstCheck = true;
            LastTriggerTime = DateTime.MinValue;
            CurrentState = false;
            LastState = false;
        }

        public void OnPropertiesChanged()
        {
            OnPropertyChanged(nameof(SignalType));
            OnPropertyChanged(nameof(SignalTypeColor));
            OnPropertyChanged(nameof(StateColor));
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);

        public void Execute(object parameter) => _execute(parameter);
    }
}